﻿using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using EpiNEXT.Core;

namespace EpiNEXT.Data
{
    /// <summary>
    /// Abstract base type for databases
    /// </summary>
    public abstract class DbDriverBase : ObservableObject, IDbDriver, IDisposable
    {
        #region Members
        private double _progress = 0;
        private string _connectionString = String.Empty;
        private bool _isProcessing = false;
        #endregion Members

        #region Properties
        public double ProcessingProgress
        {
            get
            {
                return this._progress;
            }
            set
            {
                this._progress = value;
                RaisePropertyChanged("ProcessingProgress");
            }
        }

        public string ConnectionString
        {
            get
            {
                return this._connectionString;
            }
            private set
            {
                this._connectionString = value;
            }
        }

        public bool IsProcessing
        {
            get
            {
                return this._isProcessing;
            }
            protected set
            {
                this._isProcessing = value;
                RaisePropertyChanged("IsProcessing");
            }
        }
        #endregion // Properties

        #region Constructors
        /// <summary>
        /// Default constructor
        /// </summary>
        [Obsolete("Use of default constructor not allowed", true)]
        public DbDriverBase()
        {
        }

        public DbDriverBase(string connectionString)
        {
            this.ConnectionString = connectionString;
            OpenConnection();
        }
        #endregion // Constructors

        #region Public Methods
        public abstract string IdentifyDatabase();
        public abstract bool SaveRecord(Form form, Record record);
        public abstract bool DeleteRecord(Form form, Record record);
        public abstract bool SoftDeleteRecord(Form form, Record record);
        public abstract void PopulateRecordCollection(DataEntryInstrument form);
        public abstract ObservableCollection<Record> GetRecordCollection(string tableName);
        public abstract Task<bool> SaveRecordAsync(Form form, Record record);
        public abstract bool SaveAllRecords(Project project);
        public abstract Task<bool> SaveAllRecordsAsync(Project project);

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion // Public Methods

        #region Protected Methods
        /// <summary>
        /// Opens the connection to the database
        /// </summary>
        protected virtual void OpenConnection()
        {
        }

        /// <summary>
        /// Closes the connection to the database
        /// </summary>
        protected virtual void CloseConnection()
        {
        }

        /// <summary>
        /// Updates an existing record
        /// </summary>
        /// <param name="form">The form that the record belongs to</param>
        /// <param name="record">The record that should be saved to the database</param>
        /// <returns>bool; whether the operation was successful</returns>
        protected abstract bool UpdateRecord(Form form, Record record);

        /// <summary>
        /// Inserts a new record
        /// </summary>
        /// <param name="form">The form that the record belongs to</param>
        /// <param name="record">The record that should be saved to the database</param>
        /// <returns>bool; whether the operation was successful</returns>
        protected abstract bool InsertRecord(Form form, Record record);

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                // free managed resources
                CloseConnection();
            }
            // free native resources if there are any.
        }
        #endregion // Protected Methods
    }
}
